
#include "block.h"
#include "canvas.h"

using namespace Blox;

Blox::Block::Block()
	: pParent(NULL)
{
	memset( &pChildren[0], NULL, sizeof(Block*)*Settings::CHILDREN_COUNT );
}

Blox::Block::~Block()
{
	Clear();
}

void Blox::Block::Init( Block * parent, AABB const & rBox )
{
	Clear();
	vBox.Set(rBox);
	pParent = parent;
	memset( &pChildren[0], NULL, sizeof(Block*)*Settings::CHILDREN_COUNT );
}

void Blox::Block::Init( Block * parent, Bounds const & rBounds )
{
	Clear();
	vBox.Set(rBounds);
	pParent = parent;
}

void Blox::Block::Clear()
{
	for( u32 i=0; i<Settings::CHILDREN_COUNT; i++ )
	{
		if( pChildren[i] )
		{
			delete pChildren[i];
			pChildren[i] = NULL;
		}
	}
	pParent = NULL;
}

//////////////////////////////////////////////////////////////////////////

void Blox::Block::Add( OBB const & rblockage )
{
	if( vBox.LongestSide() > 3.0f )
	{
		Split();

		for( u32 i=0; i<Settings::CHILDREN_COUNT; i++ )
		{
			pChildren[i]->Add( rblockage );
		}
	}
}

void Blox::Block::Split()
{
	if( IsSplit() )
	{
		return;
	}

	Bounds bounds(vBox);
	Vec vHalfExt(vBox.vExtents*0.5f);

	Vec vHalfExtX(vHalfExt.x,0.0f,0.0f);
	Vec vHalfExtY(0.0f,vHalfExt.y,0.0f);
	Vec vHalfExtZ(0.0f,0.0f,vHalfExt.z);

	pChildren[0] = new Block();
	pChildren[1] = new Block();
	pChildren[2] = new Block();
	pChildren[3] = new Block();
	pChildren[4] = new Block();
	pChildren[5] = new Block();
	pChildren[6] = new Block();
	pChildren[7] = new Block();

	pChildren[0]->Init( this, AABB(vBox.vCentre-vHalfExtX-vHalfExtY-vHalfExtZ,vHalfExt) );
	pChildren[1]->Init( this, AABB(vBox.vCentre+vHalfExtX-vHalfExtY-vHalfExtZ,vHalfExt) );
	pChildren[2]->Init( this, AABB(vBox.vCentre-vHalfExtX+vHalfExtY-vHalfExtZ,vHalfExt) );
	pChildren[3]->Init( this, AABB(vBox.vCentre+vHalfExtX+vHalfExtY-vHalfExtZ,vHalfExt) );
	pChildren[4]->Init( this, AABB(vBox.vCentre-vHalfExtX-vHalfExtY+vHalfExtZ,vHalfExt) );
	pChildren[5]->Init( this, AABB(vBox.vCentre+vHalfExtX-vHalfExtY+vHalfExtZ,vHalfExt) );
	pChildren[6]->Init( this, AABB(vBox.vCentre-vHalfExtX+vHalfExtY+vHalfExtZ,vHalfExt) );
	pChildren[7]->Init( this, AABB(vBox.vCentre+vHalfExtX+vHalfExtY+vHalfExtZ,vHalfExt) );
}

void Blox::Block::Report() const
{
	Report(0);
}

void Blox::Block::Report( u32 uDepth ) const
{
	for( u32 i=0; i<uDepth; i++ )
		printf(" ");

	printf( "Block - Centre[%.2f,%.2f,%.2f] Dims[%.2f,%.2f,%.2f]\n", vBox.vCentre.x, vBox.vCentre.y, vBox.vCentre.z, vBox.vExtents.x*2.0f, vBox.vExtents.y*2.0f, vBox.vExtents.z*2.0f );

	if( IsSplit() )
	{
		for( u32 i=0; i<Settings::CHILDREN_COUNT; i++ )
		{
			pChildren[i]->Report( uDepth+1 );
		}
	}
}

void Blox::Block::DrawRecursive() const
{
	if( pChildren[0] )
	{
		for( u32 i=0; i<Settings::CHILDREN_COUNT; i++ )
		{
			if( pChildren[i] )
			{
				pChildren[i]->DrawRecursive( );
			}
		}
	}
	else
	{
		Draw();
	}
}

void Blox::Block::Draw() const
{
	Canvas::m_pDefault->Draw( vBox, Col::WHITE.c32 );
}

Block * Blox::Block::GetEncompassingBlock( Bounds const & rObject ) const
{
	if( Encompasses(rObject) )
	{
		for( u32 i=0; i<Settings::CHILDREN_COUNT; i++ )
		{
			if( pChildren[i] )
			{
				Block * pBlock = pChildren[i]->GetEncompassingBlock( rObject );
				if( pBlock )
				{
					return pBlock;
				}
			}
		}
		return const_cast<Block*>(this);
	}
	else
	{
		return NULL;
	}
}

bool Blox::Block::Encompasses( Bounds const & rObject ) const
{
	return vBox.Contains(rObject);
}
